package com.wl.cloud.datax.common.utils;

import com.wl.cloud.core.exception.CustomException;
import com.wl.cloud.datax.common.enums.FrameworkCustomErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author: wanglin
 * @date: 2023-06-16 周五
 * @Version: 1.0
 * @Description:
 */
@Slf4j
public class HttpClientUtil {
    private static CredentialsProvider provider;

    private CloseableHttpClient httpClient;

    private volatile static HttpClientUtil clientUtil;

    /**
     * 构建httpclient的时候一定要设置这两个参数。淘宝很多生产故障都由此引起
     */
    private static int HTTP_TIMEOUT_INMILLIONSECONDS = 5000;

    private static final int POOL_SIZE = 20;

    private static ThreadPoolExecutor asyncExecutor = RetryUtil.createThreadPoolExecutor();

    public static void setHttpTimeoutInMillionSeconds(int httpTimeoutInMillionSeconds) {
        HTTP_TIMEOUT_INMILLIONSECONDS = httpTimeoutInMillionSeconds;
    }

    public static synchronized HttpClientUtil getHttpClientUtil() {
        if (null == clientUtil) {
            synchronized (HttpClientUtil.class) {
                if (null == clientUtil) {
                    clientUtil = new HttpClientUtil();
                }
            }
        }
        return clientUtil;
    }

    public HttpClientUtil() {
//        Properties prob = SecretUtil.getSecurityProperties();
//        HttpClientUtil.setBasicAuth(prob.getProperty("auth.user"), prob.getProperty("auth.pass"));
        initApacheHttpClient();
    }

    public void destroy() {
        destroyApacheHttpClient();
    }

    public static void setBasicAuth(String username, String password) {
        provider = new BasicCredentialsProvider();
        provider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(username, password));
    }

    /**
     * 创建包含connection pool与超时设置的client
     */
    private void initApacheHttpClient() {
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(HTTP_TIMEOUT_INMILLIONSECONDS)
                .setConnectTimeout(HTTP_TIMEOUT_INMILLIONSECONDS).setConnectionRequestTimeout(HTTP_TIMEOUT_INMILLIONSECONDS)
                .setStaleConnectionCheckEnabled(true).build();

        if (null == provider) {
            httpClient = HttpClientBuilder.create().setMaxConnTotal(POOL_SIZE).setMaxConnPerRoute(POOL_SIZE)
                    .setDefaultRequestConfig(requestConfig).build();
        } else {
            httpClient = HttpClientBuilder.create().setMaxConnTotal(POOL_SIZE).setMaxConnPerRoute(POOL_SIZE)
                    .setDefaultRequestConfig(requestConfig).setDefaultCredentialsProvider(provider).build();
        }
    }

    private void destroyApacheHttpClient() {
        try {
            if (httpClient != null) {
                httpClient.close();
                httpClient = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static HttpGet getGetRequest() {
        return new HttpGet();
    }

    public static HttpPost getPostRequest() {
        return new HttpPost();
    }

    public static HttpPut getPutRequest() {
        return new HttpPut();
    }

    public static HttpDelete getDeleteRequest() {
        return new HttpDelete();
    }

    public String executeAndGet(HttpRequestBase httpRequestBase) throws Exception {
        HttpResponse response;
        String entiStr = "";
        try {
            response = httpClient.execute(httpRequestBase);

            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                System.err.println("请求地址：" + httpRequestBase.getURI() + ", 请求方法：" + httpRequestBase.getMethod()
                        + ",STATUS CODE = " + response.getStatusLine().getStatusCode());
                if (httpRequestBase != null) {
                    httpRequestBase.abort();
                }
                throw new Exception("Response Status Code : " + response.getStatusLine().getStatusCode());
            } else {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    entiStr = EntityUtils.toString(entity, Consts.UTF_8);
                } else {
                    throw new Exception("Response Entity Is Null");
                }
            }
        } catch (Exception e) {
            throw e;
        }

        return entiStr;
    }

    public String executeAndGetWithRetry(final HttpRequestBase httpRequestBase, final int retryTimes, final long retryInterval) {
        try {
            return RetryUtil.asyncExecuteWithRetry(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return executeAndGet(httpRequestBase);
                }
            }, retryTimes, retryInterval, true, HTTP_TIMEOUT_INMILLIONSECONDS + 1000, asyncExecutor);
        } catch (Exception e) {
            throw CustomException.asCustomException(FrameworkCustomErrorCode.RUNTIME_ERROR, e);
        }
    }

    public String executeAndGetWithFailedRetry(final HttpRequestBase httpRequestBase, final int retryTimes, final long retryInterval) {
        try {
            return RetryUtil.asyncExecuteWithRetry(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    String result = executeAndGet(httpRequestBase);
                    if (result != null && result.startsWith("{\"result\":-1")) {
                        throw CustomException.asCustomException(FrameworkCustomErrorCode.CALL_REMOTE_FAILED, "远程接口返回-1,将重试");
                    }
                    return result;
                }
            }, retryTimes, retryInterval, true, HTTP_TIMEOUT_INMILLIONSECONDS + 1000, asyncExecutor);
        } catch (Exception e) {
            throw CustomException.asCustomException(FrameworkCustomErrorCode.RUNTIME_ERROR, e);
        }
    }

    public static boolean post(String serverUrl, String data, long timeout) {
        StringBuilder responseBuilder = null;
        BufferedReader reader = null;
        OutputStreamWriter wr = null;

        URL url;
        try {
            url = new URL(serverUrl);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);
            conn.setConnectTimeout(1000 * 5);
            wr = new OutputStreamWriter(conn.getOutputStream());

            wr.write(data);
            wr.flush();

            if (log.isDebugEnabled()) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                responseBuilder = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    responseBuilder.append(line).append("\n");
                }
                log.debug(responseBuilder.toString());
            }
        } catch (IOException e) {
            log.error("", e);
        } finally {

            if (wr != null) {
                try {
                    wr.close();
                } catch (IOException e) {
                    log.error("close error", e);
                }
            }

            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("close error", e);
                }
            }

        }

        return false;
    }

    public static void main(String[] args) {
//        boolean flag = post("http://www.alibaba.com/trade/search", "fsb=y&IndexArea=product_en&CatId=&SearchText=test", 6000);
        String url = "http://localhost:8088/cloud/bigdata/transfer/api/v1/task/page";
        String params = "page=0&size=20&projectId=1667088737503105026&name=任务";
//        boolean flag = post(url, params, 6000);
//        System.out.println(flag);

        RestTemplate restTemplate = new RestTemplate();
        //get请求

        //方法一：getForEntity(String url, Class<T> responseType, Object... uriVariables),没有参数

//        String url = "https://restapi.amap.com/v3/ip?key=075b6eddd825148a674dfa8a8558ac62";

        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);

        System.out.println(forEntity);
    }
}
